﻿var __extends = this.__extends || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    __.prototype = b.prototype;
    d.prototype = new __();
};
define(["require", "exports"], function(require, exports) {
    /****************************** Module Header ******************************\
    Project:            CrmRestKit
    
    Project Source:     https://crmrestkit.codeplex.com
    Version:            3.0.0-beta
    Credits:
    - ajax /encode logic: https://github.com/stackp/promisejs/blob/master/promise.js
    
    This source is subject to the Microsoft Public License.
    See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
    All other rights reserved.
    
    THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
    EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
    \***************************************************************************/
    var RestKit;
    (function (_RestKit) {
        

        

        

        

        

        

        /** A very simple promise provider */
        var VerySimplePromise = (function () {
            function VerySimplePromise() {
                this._fulfilled = null;
                this._rejected = null;
                this.state = 'pending';
                this.promise = this;
            }
            VerySimplePromise.prototype.then = function (fulfilled, rejected) {
                this._fulfilled = fulfilled;
                this._rejected = rejected;
                this.child = new VerySimplePromise();

                //If the promise is already resolved execute it immediately
                if (this.state == 'resolve')
                    this.resolve(this.resolveValue);
                else if (this.state == 'reject')
                    this.reject(this.resolveValue);

                return this.child;
            };

            //done(func: { (value: TValue): void }): IPromise<TValue> {
            //    this._fulfilled.push(func);
            //    return this;
            //}
            //fail(func: { (reason: any): void }): IPromise<TValue> {
            //    this._rejected.push(func);
            //    return this;
            //}
            //always(func: { (value: any): void }): IPromise<TValue> {
            //    this._fulfilled.push(func);
            //    this._rejected.push(func);
            //    return this;
            //}
            VerySimplePromise.prototype.reject = function (reason) {
                this.resolveValue = reason;

                this.state = 'reject';
                if (this._rejected)
                    this._rejected(this.resolveValue);
                if (this.child)
                    this.child.reject(this.resolveValue);
            };

            VerySimplePromise.prototype.resolve = function (value) {
                this.resolveValue = value;
                this.state = 'resolve';
                try  {
                    if (this._fulfilled)
                        this._fulfilled(this.resolveValue);
                    if (this.child)
                        this.child.resolve(this.resolveValue);
                } catch (e) {
                    this.reject(e);
                }
            };
            VerySimplePromise.prototype.notify = function (message) {
            };
            return VerySimplePromise;
        })();
        _RestKit.VerySimplePromise = VerySimplePromise;

        /** The restkit it self */
        var RestKit = (function () {
            /** Create a new RestKit with dependencies
            * @constructor
            * @param {delegate} defer - Method used to instaniate the promise
            * @param {delegate} [xhrProvider] - Method used to instantiate the Http Request Object.
            * @param {delegate} [contextProvider] - Method used to get the Xrm context object.
            */
            function RestKit(defer, xhrProvider, contextProvider) {
                if (typeof xhrProvider === "undefined") { xhrProvider = RestKit.getXhrInstance; }
                if (typeof contextProvider === "undefined") { contextProvider = RestKit.getContext; }
                /**
                * @const
                */
                this.ODATA_ENDPOINT = '/XRMServices/2011/OrganizationData.svc';
                this.oDataPathCache = null;
                this._deferFactory = defer;
                this._xhrProvider = xhrProvider;
                this._contextProvider = contextProvider;
            }
            RestKit.prototype.version = function () {
                return '3.0.0-beta';
            };

            /** Retrieve a record
            * @param {string} entityName Schema name of the entity
            * @param {string} id Id of the record to retrieve
            * @param {string[]} columns list of columns
            * @param {boolean} [async=true] Execute asynchrously
            */
            RestKit.prototype.Retrieve = function (entityName, id, columns) {
                var url = this.getODataPath() + "/" + entityName + "Set(guid'" + id + "')" + "?$select=" + columns.join(',');

                return this.ajax('GET', url);
            };
            RestKit.prototype.RetrieveSync = function (entityName, id, columns) {
                var url = this.getODataPath() + "/" + entityName + "Set(guid'" + id + "')" + "?$select=" + columns.join(',');

                return this.ajaxSync('GET', url);
            };

            /** Create a record
            * @param {string} entityName Schema name of the entity
            * @param {TEntity} entityObject The entity to be created
            * @param {boolean} [async=true] Execute asynchrously
            */
            RestKit.prototype.Create = function (entityName, entityObject) {
                // default is 'true'
                var setName = entityName + 'Set', data = JSON.stringify(entityObject), url = this.getODataPath() + "/" + setName;

                // returns a promise object
                return this.ajax('POST', url, data);
            };
            RestKit.prototype.CreateSync = function (entityName, entityObject) {
                // default is 'true'
                var setName = entityName + 'Set', data = JSON.stringify(entityObject), url = this.getODataPath() + "/" + setName;

                // returns a promise object
                return this.ajaxSync('POST', url, data);
            };

            /** Update a record
            * @param {string} entityName Schema name of the entity
            * @param {string} id Id of the record to update
            * @param {TEntity} entityObject The entity to be updated
            * @param {boolean} [async=true] Execute asynchrously
            */
            RestKit.prototype.Update = function (entityName, id, entityObject) {
                var setName = entityName + 'Set', url = this.getODataPath() + "/" + setName + "(guid'" + id + "')", data = JSON.stringify(entityObject), headers = {
                    'X-HTTP-Method': 'MERGE'
                };

                // MERGE methode does not return data
                return this.ajax('POST', url, data, headers);
            };
            RestKit.prototype.UpdateSync = function (entityName, id, entityObject) {
                var setName = entityName + 'Set', url = this.getODataPath() + "/" + setName + "(guid'" + id + "')", data = JSON.stringify(entityObject), headers = {
                    'X-HTTP-Method': 'MERGE'
                };

                // MERGE methode does not return data
                return this.ajaxSync('POST', url, data, headers);
            };

            /** Delete a record
            * @param {string} entityName Schema name of the entity
            * @param {string} id Id of the record to delete
            * @param {boolean} [async=true] Execute asynchrously
            */
            RestKit.prototype.Delete = function (entityName, id) {
                var setName = entityName + 'Set', url = this.getODataPath() + '/' + setName + "(guid'" + id + "')", headers = {
                    'X-HTTP-Method': 'DELETE'
                };

                return this.ajax('POST', url, null, headers);
            };
            RestKit.prototype.DeleteSync = function (entityName, id) {
                var setName = entityName + 'Set', url = this.getODataPath() + '/' + setName + "(guid'" + id + "')", headers = {
                    'X-HTTP-Method': 'DELETE'
                };

                return this.ajaxSync('POST', url, null, headers);
            };

            /** Associate two records using a M:N relation
            * @param {string} entity1Id Id of record 1
            * @param {string} entity1Name Schema name of entity 1
            * @param {string} entity2Id Id of record 2
            * @param {string} entity2Name Schema name of entity 2
            * @param {string} relationshipName Schema name of the relation
            * @param {boolean} [async=true] Execute asynchrously
            */
            RestKit.prototype.Associate = function (entity1Id, entity1Name, entity2Id, entity2Name, relationshipName) {
                var odatapath = this.getODataPath(), url = odatapath + "/" + entity1Name + "Set(guid'" + entity1Id + "')/$links/" + relationshipName, data = JSON.stringify({
                    uri: odatapath + "/" + entity2Name + "Set(guid'" + entity2Id + "')"
                });

                return this.ajax('POST', url, data);
            };
            RestKit.prototype.AssociateSync = function (entity1Id, entity1Name, entity2Id, entity2Name, relationshipName) {
                var odatapath = this.getODataPath(), url = odatapath + "/" + entity1Name + "Set(guid'" + entity1Id + "')/$links/" + relationshipName, data = JSON.stringify({
                    uri: odatapath + "/" + entity2Name + "Set(guid'" + entity2Id + "')"
                });

                return this.ajaxSync('POST', url, data);
            };

            /** Disassociate two records from a M:N relation
            * @param {string} entity1Id Id of record 1
            * @param {string} entity1Name Schema name of entity 1
            * @param {string} entity2Id Id of record 2
            * @param {string} relationshipName Schema name of the relation
            * @param {boolean} [async=true] Execute asynchrously
            */
            RestKit.prototype.Disassociate = function (entity1Id, entity1Name, entity2Id, relationshipName) {
                var url = this.getODataPath() + "/" + entity1Name + "Set(guid'" + entity1Id + "')/$links/" + relationshipName + "(guid'" + entity2Id + "')", headers = {
                    'X-HTTP-Method': 'DELETE'
                };

                return this.ajax('POST', url, null, headers);
            };
            RestKit.prototype.DisassociateSync = function (entity1Id, entity1Name, entity2Id, relationshipName) {
                var url = this.getODataPath() + "/" + entity1Name + "Set(guid'" + entity1Id + "')/$links/" + relationshipName + "(guid'" + entity2Id + "')", headers = {
                    'X-HTTP-Method': 'DELETE'
                };

                return this.ajaxSync('POST', url, null, headers);
            };

            /** Retrieve records based on the filter
            * @param {string} entityName Schema name of the entity
            * @param {string[]} columns Schema names of attributes to retrieve
            * @param {string} filter Filter
            * @param {boolean} [async=true] Execute asynchrously
            */
            RestKit.prototype.ByQuery = function (entityName, columns, filter) {
                // default is 'true'
                var setName = entityName + 'Set', url = null;

                // in case filter is empty
                filter = (filter) ? "&$filter=" + encodeURIComponent(filter) : '';
                url = this.getODataPath() + "/" + setName + "?$select=" + columns.join(',') + filter;

                return this.ajax('GET', url);
            };

            /** Retrieve records based on a full ODATA url string. Mainly used to page results.
            * @param {string} queryUrl The query string
            * @param {boolean} [async=true] Execute asynchrously
            */
            RestKit.prototype.ByQueryUrl = function (queryUrl) {
                return this.ajax('GET', queryUrl);
            };
            RestKit.prototype.ByQueryUrlSync = function (queryUrl) {
                return this.ajaxSync('GET', queryUrl);
            };

            /** Retrieve records based on the filter including related entities
            * @param {string} entityName Schema name of the entity
            * @param {string[]} columns Schema names of attributes to retrieve
            * @param {string} expand Relations to expand
            * @param {string} filter Filter
            * @param {boolean} [async=true] Execute asynchrously
            */
            RestKit.prototype.ByExpandQuery = function (entityName, columns, expand, filter) {
                var setName = entityName + 'Set', url = null;

                // in case filter is empty
                filter = (filter) ? "&$filter=" + encodeURIComponent(filter) : '';

                url = this.getODataPath() + "/" + setName + "?$select=" + columns.join(',') + '&$expand=' + expand + filter;

                return this.ajax('GET', url);
            };
            RestKit.prototype.ByExpandQuerySync = function (entityName, columns, expand, filter) {
                var setName = entityName + 'Set', url = null;

                // in case filter is empty
                filter = (filter) ? "&$filter=" + encodeURIComponent(filter) : '';

                url = this.getODataPath() + "/" + setName + "?$select=" + columns.join(',') + '&$expand=' + expand + filter;

                return this.ajaxSync('GET', url);
            };

            /** Retrieve all pages of the records based on the filter
            * @param {string} entityName Schema name of the entity
            * @param {string[]} columns Schema names of attributes to retrieve
            * @param {string} filter Filter
            * @param {boolean} [async=true] Execute asynchrously
            */
            RestKit.prototype.ByQueryAll = function (entityName, columns, filter) {
                var self = this, dfdAll = this._deferFactory(), allRecords = [];

                this.ByQuery(entityName, columns, filter).then(function byQueryAllSuccess(result) {
                    // add the elements to the collection
                    allRecords = allRecords.concat(result.d.results);

                    if (result.d.__next) {
                        // the success-handler will be this function
                        self.ByQueryUrl(result.d.__next).then(byQueryAllSuccess, dfdAll.reject);

                        // call the progressCallbacks of the promise
                        dfdAll.notify(result);
                    } else {
                        dfdAll.resolve(allRecords);
                    }
                }, dfdAll.reject);

                return dfdAll.promise;
            };

            //#region Server Url
            /**
            * Default method used to get the Xrm Context. This automatically uses Xrm.Page.context
            * or GetGlobalContext.
            */
            RestKit.getContext = function () {
                if (typeof Xrm !== 'undefined') {
                    return Xrm.Page.context;
                } else if (typeof GetGlobalContext !== 'undefined') {
                    /*ignore jslint start*/
                    return GetGlobalContext();
                    /*ignore jslint end*/
                } else {
                    throw new Error("Context is not available.");
                }
            };

            /**
            * Returns the server-url based on the current dynamics crm version
            */
            RestKit.prototype.getServerUrl = function () {
                var localServerUrl = window.location.protocol + '//' + window.location.host;
                var context = this._contextProvider();

                if (typeof context.getClientUrl == 'function') {
                    // since version SDK 5.0.13
                    // http://www.magnetismsolutions.com/blog/gayan-pereras-blog/2013/01/07/crm-2011-polaris-new-xrm.page-method
                    return context.getClientUrl();
                } else if (context.isOutlookClient() && !context.isOutlookOnline()) {
                    return localServerUrl;
                } else {
                    var url = context.getServerUrl();
                    url = url.replace(/^(http|https):\/\/([_a-zA-Z0-9\-\.]+)(:([0-9]{1,5}))?/, localServerUrl);
                    url = url.replace(/\/$/, "");

                    return url;
                }
            };

            /**
            * Returns the joined server-url and the endpoint-url
            */
            RestKit.prototype.getODataPath = function () {
                if (this.oDataPathCache == null) {
                    this.oDataPathCache = this.getServerUrl() + this.ODATA_ENDPOINT;
                }

                return this.oDataPathCache;
            };

            //#endregion
            RestKit.getXhrInstance = function () {
                var xhr;

                if (window.XMLHttpRequest) {
                    xhr = new XMLHttpRequest();
                } else if (window.ActiveXObject) {
                    try  {
                        xhr = new ActiveXObject('Msxml2.XMLHTTP');
                    } catch (e) {
                        xhr = new ActiveXObject('Microsoft.XMLHTTP');
                    }
                }
                return xhr;
            };

            /**
            * Returns all properties of the parameter as key/value pairs in a queryString.
            * @param {any} data Object to use the parameters from.
            */
            RestKit.prototype.encode = function (data) {
                var result = '';

                if (typeof data === 'string') {
                    result = data;
                } else {
                    var e = encodeURIComponent;

                    for (var key in data) {
                        if (data.hasOwnProperty(key)) {
                            result += '&' + e(key) + '=' + e(data[key]);
                        }
                    }
                }
                return result;
            };

            /**
            * Internal method to perform the actual service call
            */
            RestKit.prototype.setupXhr = function (method, url, async, headers) {
                if (typeof async === "undefined") { async = true; }
                if (typeof headers === "undefined") { headers = {}; }
                var xhr;

                xhr = this._xhrProvider();

                xhr.open(method, url, async);
                xhr.setRequestHeader('Content-type', 'application/json; charset=utf-8');
                xhr.setRequestHeader('Accept', 'application/json');

                for (var h in headers) {
                    if (headers.hasOwnProperty(h)) {
                        xhr.setRequestHeader(h, headers[h]);
                    }
                }

                return xhr;
            };

            RestKit.prototype.getResult = function (xhr) {
                if (xhr.readyState === 4) {
                    var error = (!xhr.status || (xhr.status < 200 || xhr.status >= 300) && xhr.status !== 304);

                    if (error) {
                        var reason = xhr.responseText;
                        try  {
                            reason = JSON.parse(xhr.responseText);
                        } catch (e) {
                        }

                        return {
                            success: false,
                            result: reason
                        };
                    } else {
                        return {
                            success: true,
                            result: JSON.parse(xhr.responseText)
                        };
                    }
                }
            };
            RestKit.prototype.ajax = function (method, url, data, headers) {
                if (typeof data === "undefined") { data = {}; }
                if (typeof headers === "undefined") { headers = {}; }
                var deferred = this._deferFactory();
                var payload = this.encode(data);
                if (method == 'GET' && payload) {
                    url += '?' + payload;
                    payload = null;
                }
                var xhr;
                try  {
                    xhr = this.setupXhr(method, url, true, headers);
                } catch (e) {
                    deferred.reject(e);
                    return;
                }

                var self = this;
                xhr.onreadystatechange = function () {
                    var result = self.getResult(xhr);
                    if (result.success)
                        deferred.resolve(result.result);
                    else
                        deferred.reject(result.result);
                };

                xhr.send(payload);

                return deferred.promise;
            };
            RestKit.prototype.ajaxSync = function (method, url, data, headers) {
                if (typeof data === "undefined") { data = {}; }
                if (typeof headers === "undefined") { headers = {}; }
                var payload = this.encode(data);
                if (method == 'GET' && payload) {
                    url += '?' + payload;
                    payload = null;
                }
                var xhr;
                xhr = this.setupXhr(method, url, false, headers);

                var self = this;

                xhr.send(payload);

                var result = self.getResult(xhr);

                if (result.success)
                    return result.result;
                else
                    throw new Error(result.result);
            };
            return RestKit;
        })();
        _RestKit.RestKit = RestKit;
        var ExecutionResult = (function () {
            function ExecutionResult() {
            }
            return ExecutionResult;
        })();

        //TBD provide typed versions?
        /**
        *  RestKit with typed results using JQuery Defer
        */
        var RestKitJQuery = (function (_super) {
            __extends(RestKitJQuery, _super);
            function RestKitJQuery() {
                _super.apply(this, arguments);
            }
            RestKitJQuery.prototype.Retrieve = function (entityName, id, columns) {
                return _super.prototype.Retrieve.call(this, entityName, id, columns);
            };
            return RestKitJQuery;
        })(RestKit);
        _RestKit.RestKitJQuery = RestKitJQuery;

        /** create a new RestKit using JQuery as the promise provider */
        function createJQuery($) {
            return new RestKitJQuery(function () {
                return new JQueryDeferAdaptor(($).Deferred());
            });
        }
        _RestKit.createJQuery = createJQuery;

        /** create a new RestKit using Q as the promise provider */
        function createQ() {
            return new RestKit(function () {
                return Q.defer();
            });
        }
        _RestKit.createQ = createQ;

        /** Create a new RestKit using any promise provider */
        function createOther(createDefer) {
            return new RestKit(createDefer);
        }
        _RestKit.createOther = createOther;

        /** Create a new RestKit using Bluebird as the promise provider */
        function createBlueBird(xhr) {
            return new RestKit(function () {
                return new BlueBirdAdaptor(Promise.defer());
            }, xhr);
        }
        _RestKit.createBlueBird = createBlueBird;

        /** Use the first available promise provider (BlueBird, Q, JQuery, VerySimple)*/
        function create() {
            if (typeof Promise != 'undefined')
                return createBlueBird();
            else if (typeof Q != 'undefined' && Q.defer)
                return createQ();
            else if (typeof jQuery != 'undefined')
                return createJQuery(jQuery);
            else
                return createOther(function () {
                    return new VerySimplePromise();
                });

            throw new Error('No promise provider available');
        }
        _RestKit.create = create;

        /** Maps notify to progress  */
        var BlueBirdAdaptor = (function () {
            function BlueBirdAdaptor(defer) {
                this.defer = defer;
                this.promise = defer.promise;
            }
            BlueBirdAdaptor.prototype.reject = function (reason) {
                this.defer.reject(reason);
            };
            BlueBirdAdaptor.prototype.resolve = function (reason) {
                this.defer.resolve(reason);
            };
            BlueBirdAdaptor.prototype.notify = function (message) {
                this.defer.progress(message);
            };
            return BlueBirdAdaptor;
        })();
        _RestKit.BlueBirdAdaptor = BlueBirdAdaptor;

        /** Add the promise property */
        var JQueryDeferAdaptor = (function () {
            function JQueryDeferAdaptor(defer) {
                this.defer = defer;
                this.promise = defer;
            }
            JQueryDeferAdaptor.prototype.reject = function (reason) {
                return new JQueryDeferAdaptor(this.defer.reject(reason));
            };
            JQueryDeferAdaptor.prototype.resolve = function (reason) {
                return new JQueryDeferAdaptor(this.defer.resolve(reason));
            };
            JQueryDeferAdaptor.prototype.notify = function (message) {
                this.defer.notify(message);
            };
            return JQueryDeferAdaptor;
        })();
        _RestKit.JQueryDeferAdaptor = JQueryDeferAdaptor;

        (function (util) {
            /**
            * Returns an object that reprensts a entity-reference
            */
            function entityReferenceFactory(id, logicalName) {
                if (typeof logicalName === "undefined") { logicalName = null; }
                if (id !== undefined && id !== null) {
                    return {
                        Id: id,
                        __metadata: { type: 'Microsoft.Crm.Sdk.Data.Services.EntityReference' },
                        LogicalName: logicalName,
                        Name: null
                    };
                }

                return null;
            }
            util.entityReferenceFactory = entityReferenceFactory;

            /**
            * Creates an object that reprensts a option-set-value
            */
            function optionSetValueFactory(value) {
                return {
                    Value: value,
                    __metadata: { type: 'Microsoft.Crm.Sdk.Data.Services.OptionSetValue' }
                };
            }
            util.optionSetValueFactory = optionSetValueFactory;

            /**
            * Returns an object that represents an money value
            */
            function moneyValueFactory(value) {
                return {
                    Value: value,
                    __metadata: { type: 'Microsoft.Crm.Sdk.Data.Services.Money' }
                };
            }
            util.moneyValueFactory = moneyValueFactory;

            //#endregion
            /**
            * Parses the ODATA date-string into a date-object
            * All queries return a date in the format "/Date(1368688809000)/"
            */
            function parseODataDate(value) {
                return new Date(parseInt(value.replace('/Date(', '').replace(')/', ''), 10));
            }
            util.parseODataDate = parseODataDate;
        })(_RestKit.util || (_RestKit.util = {}));
        var util = _RestKit.util;
    })(RestKit || (RestKit = {}));
    
    return RestKit;
});
//# sourceMappingURL=CrmRestKit.js.map
